//
// Created by zhouwd on 2020/3/9.
//

#include "render.h"
#include <math.h>

#define ATTRIB_TEXTURE_IMAGE1 2
#define ATTRIB_TEXTURE_IMAGE2 3
#define ATTRIB_TEXTURE_IMAGE3 4
#define ATTRIB_TEXTURE_IMAGE2_POSITION 5

bool checkGlError(const char* funcName) {
    GLint err = glGetError();
    if (err != GL_NO_ERROR) {
        printf("GL error after %s(): 0x%08x\n", funcName, err);
        return true;
    }
    return false;
}
GLuint VAO[6];
GLuint VBO[7];
GLuint FBO[2];
GLuint DRBO[2];

#define ATTRIB_TEXTURE 1

GLubyte pixels[4 * 3] ={
    255, 255, 0,
    0, 255, 0,
    0, 0, 255,
    255, 255, 0,
};

GLubyte pixels2[4 * 4] ={
        255, 0, 0,255,
        0, 255, 0,255,
        0, 0, 255,255,
        255, 255, 0,255,
};

GLfloat  vTextureImage0Position[] = {
        -1.0f, -1.0f, 0.0f,
        -1.0f, 1.0f, 0.0f,

        1.0f, -1.0f, 0.0f,
        1.0f, 1.0f, 0.0f,
};

GLfloat  vTextureImage1Position[] = {
        0.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,

        0.0f, 1.0f, 0.0f,
        1.0f, 1.0f, 0.0f,
};

GLfloat vTextureImage2Position[] = {
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        1.0f, 1.0f, 0.0f,
};

GLfloat vTextureImage3Position[] = {
        0.5f, 0.5f, 0.0f,
        0.5f, 0.8f, 0.0f,
        0.8f, 0.8f, 0.0f,
        0.8f, 0.5f, 0.0f,
};

GLfloat  vTextureImage1[] = {
        0.0f,  1.0f,
        1.0f,  1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
};

GLfloat vTextureImage2[] = {
        0.0f,  1.0f,
        1.0f,  1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
};

GLfloat vTextureImage3[] = {
        0.0f,  1.0f,
        1.0f,  1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
};

GLfloat  vMatrix[] = {
        0.5f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.5f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.5f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f,
};

GLfloat  vMatrix1[] = {
        0.7f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.7f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.7f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f,
};

GLfloat  vMatrix2[] = {
        1.2f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.2f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.2f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f,
};

GLfloat vDiamond[] = {
        -1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        -0.5f, 1.0f, 0.0f,

        -1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        -0.5f, -1.0f, 0.0f,
};

GLfloat vSquare[] = {
        0.8f, 0.0f, 0.0f,
        0.3f, 0.5f, 0.0f,
        0.3f, 0.0f, 0.0f,

        0.8f, 0.0f, 0.0f,
        0.3f, 0.5f, 0.0f,
        0.8f, 0.5f, 0.0f,
};

GLfloat vCircle[364 * 3];

int OPENGL_LEARN_RENDER::init(char *mPreviewFragmentShaderBuffer, char *mPreviewVertexShaderBuffer) {

    program = createProgram(mPreviewVertexShaderBuffer, mPreviewFragmentShaderBuffer);
    //program = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
    if (!program){
        ALOGE("程序创建失败");
        return -1;
    }

    free(mPreviewFragmentShaderBuffer);
    free(mPreviewVertexShaderBuffer);
    glClearColor(0,0,0,0);

    return 0;
}

GLuint OPENGL_LEARN_RENDER::createProgram(const char *vtxSrc, const char *fragSrc) {
    GLuint vtxShader = 0;
    GLuint fragShader = 0;
    GLuint program = 0;
    GLint linked = GL_FALSE;
    vtxShader = createShader(GL_VERTEX_SHADER, vtxSrc);
    if (!vtxShader){
        ALOGE("Could not create vertext shader");
        goto exit;
    }

    fragShader = createShader(GL_FRAGMENT_SHADER, fragSrc);
    if (!fragShader){
        ALOGE("Could not create fragment shader");
        goto exit;
    }

    program = glCreateProgram();
    if (!program) {
        checkGlError("glCreateProgram");
        goto exit;
    }
    glAttachShader(program, vtxShader);
    glAttachShader(program, fragShader);



    glGenBuffers(6, VBO);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vDiamond), vDiamond, GL_STATIC_DRAW);
//
    glBindBuffer(GL_ARRAY_BUFFER,VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vSquare), vSquare, GL_STATIC_DRAW);

    vCircle[0] = 0.5f;
    vCircle[1] = -0.5f;
    vCircle[2] = 0.0f;

    for (int i = 1; i < 364; ++i) {
        vCircle[(i * 3)+ 0] = (float)(0.3f * cos((3.14/180) * i ) + 0.5f);
        vCircle[(i * 3)+ 1] = (float)(0.3f * sin((3.14/180) * i ) - 0.5f);
        vCircle[(i * 3)+ 2] = 0.0f;
    }

    glBindBuffer(GL_ARRAY_BUFFER,VBO[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vCircle), vCircle, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER,VBO[3]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vTextureImage0Position), vTextureImage0Position, GL_STATIC_DRAW);
//
    glBindBuffer(GL_ARRAY_BUFFER,VBO[4]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vTextureImage1Position), vTextureImage1Position, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER,VBO[5]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vTextureImage2), vTextureImage2, GL_STATIC_DRAW);

    glBindBuffer(GL_PIXEL_PACK_BUFFER, VBO[6]);
    glBufferData(GL_PIXEL_PACK_BUFFER, 100, NULL, GL_DYNAMIC_COPY);
//
    glGenVertexArrays(6, VAO);
//
    glBindVertexArray(VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[0]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[1]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(VAO[2]);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[2]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(VAO[3]);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[3]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(VAO[4]);
    glBindBuffer(GL_ARRAY_BUFFER,VBO[4]);
    glVertexAttribPointer(ATTRIB_TEXTURE_IMAGE2_POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(ATTRIB_TEXTURE_IMAGE2_POSITION);

    glBindBuffer(GL_ARRAY_BUFFER,VBO[5]);
    glVertexAttribPointer(ATTRIB_TEXTURE_IMAGE2, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(ATTRIB_TEXTURE_IMAGE2);



    glBindVertexArray(VAO[5]);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, VBO[6]);


    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &linked);

    textureImage1 = glGetUniformLocation(program, "image1");
    textureImage2 = glGetUniformLocation(program, "image2");
//    textureImage3 = glGetUniformLocation(program, "image3");

    glGenFramebuffers(2 , FBO);
    glGenRenderbuffers(2, DRBO);

    glGenTextures(1, &image1);
    glBindTexture(GL_TEXTURE_2D, image1);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenTextures(1, &image2);
    glBindTexture(GL_TEXTURE_2D, image2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);




    if (!linked) {
        ALOGE("Could not link program");
        GLint infoLogLen = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
        if (infoLogLen) {
            GLchar* infoLog = (GLchar*)malloc(infoLogLen);
            if (infoLog) {
                glGetProgramInfoLog(program, infoLogLen, NULL, infoLog);
                ALOGE("Could not link program:\n%s\n", infoLog);
                free(infoLog);
            }
        }
        glDeleteProgram(program);
        program = 0;
    }
    exit:
    glDeleteShader(vtxShader);
    glDeleteShader(fragShader);
    return program;
}

GLuint OPENGL_LEARN_RENDER::createShader(GLenum shaderType, const char *src) {
    GLuint shader = glCreateShader(shaderType);
    if (!shader) {
        checkGlError("glCreateShader");
        return 0;
    }
    glShaderSource(shader, 1, &src, NULL);

    GLint compiled = GL_FALSE;
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    if (!compiled) {
        GLint infoLogLen = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
        if (infoLogLen > 0) {
            GLchar* infoLog = (GLchar*)malloc(infoLogLen);
            if (infoLog) {
                glGetShaderInfoLog(shader, infoLogLen, NULL, infoLog);
                printf("Could not compile %s shader:\n%s\n",
                       shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment",
                       infoLog);
                free(infoLog);
            }
        }
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

int OPENGL_LEARN_RENDER::resize(int width, int height) {
    glViewport(0, 0, width, height);
    glClear(GL_COLOR_BUFFER_BIT);
    return 0;
}

char *picTextureData;
int picTextureWidth;
int picTextureHeight;

int OPENGL_LEARN_RENDER::step() {
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);

    GLint loadImageType1 = glGetUniformLocation(program, "loadImageType");
    glUniform1i(loadImageType1, 1);

    glBindVertexArray(VAO[3]);

    glVertexAttribPointer(ATTRIB_TEXTURE_IMAGE1, 2, GL_FLOAT, GL_FALSE, 0, vTextureImage1);
    glEnableVertexAttribArray(ATTRIB_TEXTURE_IMAGE1);

    //纹理一
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, image1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels2);
    glUniform1i(textureImage1, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    //图片纹理
    GLint loadImageType2 = glGetUniformLocation(program, "loadImageType");
    glUniform1i(loadImageType2, 2);

    glBindVertexArray(VAO[4]);


    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, image2);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, picTextureWidth, picTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, picTextureData);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(textureImage2, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    GLint loadImageType3 = glGetUniformLocation(program, "loadImageType");
    glUniform1i(loadImageType3, 3);

    GLint viewMatrix = glGetUniformLocation(program, "viewMatrix");
    glUniformMatrix4fv(viewMatrix, 1, GL_FALSE, vMatrix);
    glBindVertexArray(VAO[0]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);

    GLint viewMatrix1 = glGetUniformLocation(program, "viewMatrix");
    glUniformMatrix4fv(viewMatrix1, 1, GL_FALSE, vMatrix1);
    glBindVertexArray(VAO[1]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);

    GLint viewMatrix2 = glGetUniformLocation(program, "viewMatrix");
    glUniformMatrix4fv(viewMatrix2, 1, GL_FALSE, vMatrix2);
    glBindVertexArray(VAO[2]);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 364);

    //glCompressedTexImage2D()
    //glReadPixels()
    glBindVertexArray(0);

    return 0;
}



int OPENGL_LEARN_RENDER::setPicTexture(char *data, int size, int width, int height) {
    ALOGE("setPicTexture -> data -> %s", data);
    ALOGE("setPicTexture -> size -> %d -- width -> %d -- height -> %d", sizeof(data), width, height);
    picTextureData = (char *)malloc(size);

    memcpy(picTextureData, data, size);
    //ALOGE("setPicTexture -> data -> %d", sizeof(picTextureData));
//    FILE *fp;
//
//    fp = fopen( "/storage/emulated/0/file.rgba" , "w" );
//    fwrite(picTextureData, size , 1, fp );
//
//    fclose(fp);

    picTextureWidth = width;
    picTextureHeight = height;

    return 0;
}

int OPENGL_LEARN_RENDER::change() {
    ALOGE("OPENGL_LEARN_RENDER -> change ->");


    return 0;
}
